﻿using Xejen.Communication.Configuration;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Xejen.Communication
{
    /// <summary>
    /// 表示默认的通讯心跳机制的具体实现
    /// </summary>
    /// <typeparam name="THeartbeatConfig"><inheritdoc cref="Xejen.Communication.Configuration.HeartbeatConfig" path="/summary"/></typeparam>
    /// <creator>marc</creator>
    public class CommunicationHeartbeat<THeartbeatConfig> : IHeartbeat<THeartbeatConfig>, IHostedService
        where THeartbeatConfig : HeartbeatConfig, new()
    {
        private readonly Timer _heartbeatTimer;
        /// <inheritdoc/>
        public THeartbeatConfig HeartbeatConfig { get; }

        /// <inheritdoc/>
        public bool IsLocalAlive { get; protected set; }
        /// <inheritdoc/>
        public bool IsRemoteAlive { get; protected set; }

        /// <inheritdoc/>
        public Func<bool> RemoteHeartbeatCheck { get; set; }
        /// <inheritdoc/>
        public Func<bool> LocalHeartbeatCheck { get; set; }

        /// <inheritdoc/>
        public event EventHandler<AliveStatusEventArgs> LocalAliveChanged;
        /// <inheritdoc/>
        public event EventHandler<AliveStatusEventArgs> RemoteAliveChanged;

        /// <inheritdoc cref="CommunicationHeartbeat{THeartbeatConfig}"/>
        public CommunicationHeartbeat(THeartbeatConfig heartbeatConfig)
        {
            Check.NotNull(heartbeatConfig, nameof(heartbeatConfig));

            HeartbeatConfig = heartbeatConfig;

            Timer heartbeatTimer = new Timer(heartbeatConfig.Interval);
            heartbeatTimer.Elapsed += HeartbeatTimer_Elapsed;
            if (heartbeatConfig.Interval <= 0)
            {
                heartbeatTimer.AutoReset = false;
            }

            _heartbeatTimer = heartbeatTimer;
        }

        private void HeartbeatTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            CheckLocalHeartbeat();
            CheckRemoteHeartbeat();
        }

        /// <summary>
        /// 检测本地在线状态
        /// </summary>
        private void CheckLocalHeartbeat()
        {
            bool alive = false;
            if (this.LocalHeartbeatCheck != null)
            {
                alive = this.LocalHeartbeatCheck.Invoke();
            }
            if (IsLocalAlive != alive)
            {
                OnLocalAliveChanged(this, new AliveStatusEventArgs(alive));
            }

            IsLocalAlive = alive;
        }
        /// <summary>
        /// 检测远端在线状态
        /// </summary>
        private void CheckRemoteHeartbeat()
        {
            bool alive = false;
            if (this.RemoteHeartbeatCheck != null)
            {
                alive = this.RemoteHeartbeatCheck.Invoke();
            }
            if (IsRemoteAlive != alive)
            {
                OnRemoteAliveChanged(this, new AliveStatusEventArgs(alive));
            }

            IsRemoteAlive = alive;
        }

        /// <summary>
        /// 设置心跳检测逻辑函数
        /// </summary>
        /// <param name="checker"><inheritdoc cref="IHeartbeatChecker" path="/summary"/></param>
        internal void SetHeartbeatCheckFunction(IHeartbeatChecker checker)
        {
            LocalHeartbeatCheck = checker?.LocalHeartbeatCheck;
            RemoteHeartbeatCheck = checker?.RemoteHeartbeatCheck;
        }

        /// <summary>
        /// 当本地在线状态变更时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected virtual void OnLocalAliveChanged(object sender, AliveStatusEventArgs args)
        {
            this.LocalAliveChanged?.Invoke(sender, args);
        }
        /// <summary>
        /// 当远端在线状态变更时发生
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="args"></param>
        protected virtual void OnRemoteAliveChanged(object sender, AliveStatusEventArgs args)
        {
            this.RemoteAliveChanged?.Invoke(sender, args);
        }

        /// <inheritdoc/>
        public async Task StartAsync(System.Threading.CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            if (!HeartbeatConfig.Enable)
            {
                return;
            }
            _heartbeatTimer.Start();

            await Task.CompletedTask;
        }

        /// <inheritdoc/>
        public async Task StopAsync(System.Threading.CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return;
            }
            if (!HeartbeatConfig.Enable)
            {
                return;
            }
            _heartbeatTimer.Stop();

            await Task.CompletedTask;
        }
    }
}
